home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / libs / tsipp / tsipp.lha / tsipp3.0a / src / tSippUtil.c < prev   
Encoding:
C/C++ Source or Header  |  1992-11-02  |  30.5 KB  |  881 lines

  1. /*
  2.  *=============================================================================
  3.  *                                  tSippUtil.c
  4.  *-----------------------------------------------------------------------------
  5.  * Utility procedures.
  6.  *-----------------------------------------------------------------------------
  7.  * Copyright 1992 Mark Diekhans
  8.  * Permission to use, copy, modify, and distribute this software and its
  9.  * documentation for any purpose and without fee is hereby granted, provided
  10.  * that the above copyright notice appear in all copies.  Mark Diekhans makes
  11.  * no representations about the suitability of this software for any purpose.
  12.  * It is provided "as is" without express or implied warranty.
  13.  *-----------------------------------------------------------------------------
  14.  * $Id: tSippUtil.c,v 2.0 1992/11/02 03:56:35 markd Rel $
  15.  *============================================================================
  16.  */
  17.  
  18. #include "tSippInt.h"
  19.  
  20. /*
  21.  * Implied column 3 of the Transf_mat.
  22.  */
  23. static double matrixCol3 [] = {0.0, 0.0, 0.0, 1.0};
  24.  
  25. /*=============================================================================
  26.  * TSippConvertFraction --
  27.  *   Convert a string that should be in the range 0 to 1 to a double and do
  28.  *   error checking.
  29.  * Parameters:
  30.  *   o tSippGlobPtr (I) - A pointer to the Tcl SIPP global structure.
  31.  *   o strBuf (I) - String containing the number.
  32.  *   o valuePtr (O) - The converted number is returned here.
  33.  * Returns:
  34.  *   TRUE if the number is valid, FALSE if there is an error.
  35.  *-----------------------------------------------------------------------------
  36.  */
  37. bool
  38. TSippConvertFraction (tSippGlobPtr, strBuf, valuePtr)
  39.     tSippGlob_pt  tSippGlobPtr;
  40.     char         *strBuf;
  41.     double       *valuePtr;
  42. {
  43.  
  44.     if (Tcl_GetDouble (tSippGlobPtr->interp, strBuf, valuePtr) != TCL_OK)
  45.         return FALSE;
  46.     if ((*valuePtr < 0.0) || (*valuePtr > 1.0)) {
  47.         Tcl_AppendResult (tSippGlobPtr->interp,
  48.                           "Expected a number in the range 0..1, got: ",
  49.                           strBuf, (char *) NULL);
  50.         return FALSE;
  51.     }
  52.     return TRUE;
  53.  
  54. } /* TSippConvertFraction */
  55.  
  56. /*=============================================================================
  57.  * TSippConvertUnsignedDbl --
  58.  *   Convert a string that should be in a double >= 0.0 with error checking.
  59.  * Parameters:
  60.  *   o tSippGlobPtr (I) - A pointer to the Tcl SIPP global structure.
  61.  *   o strBuf (I) - String containing the number.
  62.  *   o valuePtr (O) - The converted number is returned here.
  63.  * Returns:
  64.  *   TRUE if the number is valid, FALSE if there is an error.
  65.  *-----------------------------------------------------------------------------
  66.  */
  67. bool
  68. TSippConvertUnsignedDbl (tSippGlobPtr, strBuf, valuePtr)
  69.     tSippGlob_pt  tSippGlobPtr;
  70.     char         *strBuf;
  71.     double       *valuePtr;
  72. {
  73.  
  74.     if (Tcl_GetDouble (tSippGlobPtr->interp, strBuf, valuePtr) != TCL_OK)
  75.         return FALSE;
  76.     if (*valuePtr < 0.0) {
  77.         Tcl_AppendResult (tSippGlobPtr->interp,
  78.                           "Expected a number >= 0.0, got: ",
  79.                           strBuf, (char *) NULL);
  80.         return FALSE;
  81.     }
  82.     return TRUE;
  83.  
  84. } /* TSippConvertUnsignedDbl */
  85.  
  86. /*=============================================================================
  87.  * TSippConvertPosUnsigned --
  88.  *   Convert a string that should be in a integer > 0 with error checking.
  89.  * Parameters:
  90.  *   o tSippGlobPtr (I) - A pointer to the Tcl SIPP global structure.
  91.  *   o strBuf (I) - String containing the number.
  92.  *   o valuePtr (O) - The converted number is returned here.
  93.  * Returns:
  94.  *   TRUE if the number is valid, FALSE if there is an error.
  95.  *-----------------------------------------------------------------------------
  96.  */
  97. bool
  98. TSippConvertPosUnsigned (tSippGlobPtr, strBuf, valuePtr)
  99.     tSippGlob_pt  tSippGlobPtr;
  100.     char         *strBuf;
  101.     unsigned     *valuePtr;
  102. {
  103.  
  104.     if (Tcl_GetUnsigned (tSippGlobPtr->interp, strBuf, valuePtr) != TCL_OK)
  105.         return FALSE;
  106.     if (*valuePtr == 0) {
  107.         Tcl_AppendResult (tSippGlobPtr->interp, "Expected a number > 0, got: ",
  108.                           strBuf, (char *) NULL);
  109.         return FALSE;
  110.     }
  111.     return TRUE;
  112.  
  113. } /* TSippConvertPosUnsigned */
  114.  
  115. /*=============================================================================
  116.  * TSippConvertColor --
  117.  *   Convert a three element list of color values to float point numbers and
  118.  * validate that they are in range.
  119.  *
  120.  * Parameters:
  121.  *   o tSippGlobPtr (I) - A pointer to the Tcl SIPP global structure.
  122.  *   o listStr (I) - Tcl list containing the color values to convert.
  123.  *   o colorPtr (O) - The converted color values are returned here.
  124.  * Returns:
  125.  *   TRUE if the list and numbers are valid, FALSE if there is an error.
  126.  *-----------------------------------------------------------------------------
  127.  */
  128. bool
  129. TSippConvertColor (tSippGlobPtr, listStr, colorPtr)
  130.     tSippGlob_pt  tSippGlobPtr;
  131.     char         *listStr;
  132.     Color        *colorPtr;
  133. {
  134.     int    listArgc;
  135.     char **listArgv;
  136.  
  137.     if (Tcl_SplitList (tSippGlobPtr->interp, listStr, &listArgc,
  138.                        &listArgv) != TCL_OK)
  139.         return FALSE;
  140.  
  141.     if (listArgc != 3) {
  142.         Tcl_AppendResult (tSippGlobPtr->interp,
  143.                           "color must be a list of three elements",
  144.                           (char *) NULL);
  145.         goto errorCleanup;
  146.     }
  147.     if (!TSippConvertFraction (tSippGlobPtr, listArgv [0], &colorPtr->red))
  148.         goto errorCleanup;
  149.     if (!TSippConvertFraction (tSippGlobPtr, listArgv [1], &colorPtr->grn))
  150.         goto errorCleanup;
  151.     if (!TSippConvertFraction (tSippGlobPtr, listArgv [2], &colorPtr->blu))
  152.         goto errorCleanup;
  153.  
  154.     ckfree (listArgv);
  155.     return TRUE;
  156.     
  157. errorCleanup:
  158.     ckfree (listArgv);
  159.     return FALSE;
  160.  
  161. } /* TSippConvertColor */
  162.  
  163. /*=============================================================================
  164.  * TSippConvertOpacity --
  165.  *   Convert a list specifying opacity values to float point numbers and
  166.  *  validate that they are in range.  The list may be either a single value, or
  167.  *  a set of red, blue and green values.
  168.  *
  169.  * Parameters:
  170.  *   o tSippGlobPtr (I) - A pointer to the Tcl SIPP global structure.
  171.  *   o listStr (I) - Tcl list containing the opacity values to convert.
  172.  *   o opacityPtr (O) - The converted opacity values are returned here.
  173.  * Returns:
  174.  *   TRUE if the list and numbers are valid, FALSE if there is an error.
  175.  *-----------------------------------------------------------------------------
  176.  */
  177. bool
  178. TSippConvertOpacity (tSippGlobPtr, listStr, opacityPtr)
  179.     tSippGlob_pt  tSippGlobPtr;
  180.     char         *listStr;
  181.     Color        *opacityPtr;
  182. {
  183.     int    listArgc;
  184.     char **listArgv;
  185.  
  186.     if (Tcl_SplitList (tSippGlobPtr->interp, listStr, &listArgc,
  187.                        &listArgv) != TCL_OK)
  188.         return FALSE;
  189.  
  190.     if (!((listArgc == 1) || (listArgc == 3))) {
  191.         Tcl_AppendResult (tSippGlobPtr->interp, "opacity must be a single ",
  192.                           "number or a list of three elements",
  193.                           (char *) NULL);
  194.         goto errorCleanup;
  195.     }
  196.     if (listArgc == 1) {
  197.         if (!TSippConvertFraction (tSippGlobPtr, listArgv [0],
  198.                                    &opacityPtr->red))
  199.             goto errorCleanup;
  200.         opacityPtr->blu = opacityPtr->grn = opacityPtr->red;
  201.     } else {
  202.         if (!TSippConvertFraction (tSippGlobPtr, listArgv [0],
  203.                                    &opacityPtr->red))
  204.             goto errorCleanup;
  205.         if (!TSippConvertFraction (tSippGlobPtr, listArgv [1],
  206.                                    &opacityPtr->grn))
  207.             goto errorCleanup;
  208.         if (!TSippConvertFraction (tSippGlobPtr, listArgv [2],
  209.                                    &opacityPtr->blu))
  210.             goto errorCleanup;
  211.     }
  212.     ckfree (listArgv);
  213.     return TRUE;
  214.     
  215. errorCleanup:
  216.     ckfree (listArgv);
  217.     return FALSE;
  218.  
  219. } /* TSippConvertOpacity */
  220.  
  221. /*=============================================================================
  222.  * TSippConvertAngleRad --
  223.  *   Convert a string that should represents a angle to radians.   The value
  224.  *   may be in degrees or radians.  If it is prefixed with 'D' it is taken
  225.  *   to be degrees, if it is prefixed with 'R', it is taken to be radians.
  226.  *   If neither is specified, radians is assumed.
  227.  *
  228.  * Parameters:
  229.  *   o tSippGlobPtr (I) - A pointer to the Tcl SIPP global structure.
  230.  *   o strBuf (I) - String containing the angle
  231.  *   o valuePtr (O) - The converted angle is returned here (in radians).
  232.  * Returns:
  233.  *   TRUE if the number is valid, FALSE if there is an error.
  234.  *-----------------------------------------------------------------------------
  235.  */
  236. bool
  237. TSippConvertAngleRad (tSippGlobPtr, strBuf, valuePtr)
  238.     tSippGlob_pt  tSippGlobPtr;
  239.     char         *strBuf;
  240.     double       *valuePtr;
  241. {
  242.     char *strStartPtr = strBuf;
  243.  
  244.     if ((strStartPtr [0] == 'D') || (strStartPtr [0] == 'R'))
  245.         strStartPtr++;
  246.  
  247.     if (Tcl_GetDouble (tSippGlobPtr->interp, strStartPtr, valuePtr) != TCL_OK)
  248.         return FALSE;
  249.  
  250.     if (strBuf [0] == 'D')
  251.        *valuePtr = (*valuePtr * M_PI) / 180.0;
  252.     return TRUE;
  253.  
  254. } /* TSippConvertAngleRad */
  255.  
  256. /*=============================================================================
  257.  * TSippConvertAngleDeg --
  258.  *   Convert a string that should represents a angle to degrees.   The value
  259.  *   may be in degrees or radians.  If it is prefixed with 'D' it is taken
  260.  *   to be degrees, if it is prefixed with 'R', it is taken to be radians.
  261.  *   If neither is specified, degrees is assumed.
  262.  *
  263.  * Parameters:
  264.  *   o tSippGlobPtr (I) - A pointer to the Tcl SIPP global structure.
  265.  *   o strBuf (I) - String containing the angle
  266.  *   o valuePtr (O) - The converted angle is returned here (in degress).
  267.  * Returns:
  268.  *   TRUE if the number is valid, FALSE if there is an error.
  269.  *-----------------------------------------------------------------------------
  270.  */
  271. bool
  272. TSippConvertAngleDeg (tSippGlobPtr, strBuf, valuePtr)
  273.     tSippGlob_pt  tSippGlobPtr;
  274.     char         *strBuf;
  275.     double       *valuePtr;
  276. {
  277.     char *strStartPtr = strBuf;
  278.  
  279.     if ((strStartPtr [0] == 'D') || (strStartPtr [0] == 'R'))
  280.         strStartPtr++;
  281.  
  282.     if (Tcl_GetDouble (tSippGlobPtr->interp, strStartPtr, valuePtr) != TCL_OK)
  283.         return FALSE;
  284.  
  285.     if (strBuf [0] == 'R')
  286.        *valuePtr = (*valuePtr * 180.0) / M_PI;
  287.     return TRUE;
  288.  
  289. } /* TSippConvertAngleDeg */
  290.  
  291. /*=============================================================================
  292.  * TSippConvert2DPoint --
  293.  *   Convert a list of two numbers repersenting a point in 2D space to floaing
  294.  * point numbers.
  295.  *
  296.  * Parameters:
  297.  *   o tSippGlobPtr (I) - A pointer to the Tcl SIPP global structure.
  298.  *   o listStr (I) - A Tcl list containing the vector values to convert.
  299.  *   o xCoordPtr (O) - The X coordinate is returned here.
  300.  *   o yCoordPtr (O) - The Y coordinate is returned here.
  301.  * Returns:
  302.  *   TRUE if the list and numbers are valid, FALSE if there is an error.
  303.  *-----------------------------------------------------------------------------
  304.  */
  305. bool
  306. TSippConvert2DPoint (tSippGlobPtr, listStr, xCoordPtr, yCoordPtr)
  307.     tSippGlob_pt  tSippGlobPtr;
  308.     char         *listStr;
  309.     double       *xCoordPtr;
  310.     double       *yCoordPtr;
  311. {
  312.     int    listArgc;
  313.     char **listArgv;
  314.  
  315.     if (Tcl_SplitList (tSippGlobPtr->interp, listStr, &listArgc,
  316.                        &listArgv) != TCL_OK)
  317.         return FALSE;
  318.  
  319.     if (listArgc != 2) {
  320.         Tcl_AppendResult (tSippGlobPtr->interp, 
  321.                           "a 2D point must be a list of two elements",
  322.                           (char *) NULL);
  323.         goto errorCleanup;
  324.     }
  325.    
  326.     if (Tcl_GetDouble (tSippGlobPtr->interp, listArgv [0],
  327.                        xCoordPtr) != TCL_OK)
  328.        goto errorCleanup;
  329.     if (Tcl_GetDouble (tSippGlobPtr->interp, listArgv [1],
  330.                        yCoordPtr) != TCL_OK)
  331.        goto errorCleanup;
  332.  
  333.     ckfree (listArgv);
  334.     return TRUE;
  335.  
  336. errorCleanup:
  337.     ckfree (listArgv);
  338.     return FALSE;
  339.  
  340. } /* TSippConvert2DPoint */
  341.  
  342. /*=============================================================================
  343.  * TSippConvertVertex --
  344.  *   Convert a list contain a list of a triple of numbers repersenting a
  345.  * vertex X, Y and Z into vertex.
  346.  *
  347.  * Parameters:
  348.  *   o tSippGlobPtr (I) - A pointer to the Tcl SIPP global structure.
  349.  *   o listStr (I) - A Tcl list containing the vertex values to convert.
  350.  *   o vertexPtr (O) - The converted vertex is returned here.
  351.  * Returns:
  352.  *   TRUE if the list and numbers are valid, FALSE if there is an error.
  353.  *-----------------------------------------------------------------------------
  354.  */
  355. bool
  356. TSippConvertVertex (tSippGlobPtr, listStr, vertexPtr)
  357.     tSippGlob_pt  tSippGlobPtr;
  358.     char         *listStr;
  359.     Vector       *vertexPtr;
  360. {
  361.     int      vertexArgc;
  362.     char   **vertexArgv;
  363.     Vector  *currentPtr;
  364.  
  365.     if (Tcl_SplitList (tSippGlobPtr->interp, listStr, &vertexArgc,
  366.                        &vertexArgv) != TCL_OK)
  367.         return FALSE;
  368.  
  369.     if (vertexArgc != 3) {
  370.         Tcl_AppendResult (tSippGlobPtr->interp, "vertex or vector must be",
  371.                          " a list of three elements", (char *) NULL);
  372.         goto errorCleanup;
  373.     }
  374.  
  375.     if (Tcl_GetDouble (tSippGlobPtr->interp, vertexArgv [0],
  376.                        &vertexPtr->x) != TCL_OK)
  377.        goto errorCleanup;
  378.     if (Tcl_GetDouble (tSippGlobPtr->interp, vertexArgv [1],
  379.                        &vertexPtr->y) != TCL_OK)
  380.        goto errorCleanup;
  381.     if (Tcl_GetDouble (tSippGlobPtr->interp, vertexArgv [2],
  382.                        &vertexPtr->z) != TCL_OK)
  383.        goto errorCleanup;
  384.     ckfree (vertexArgv);
  385.     return TRUE;
  386.  
  387. errorCleanup:
  388.     ckfree (vertexArgv);
  389.     return FALSE;
  390.  
  391. } /* TSippConvertVertex */
  392.  
  393. /*=============================================================================
  394.  * TSippConvertVertexTex --
  395.  *   Convert a list contain a list of two triples of numbers repersenting a
  396.  * vertex X, Y and Z and texture U, V and W into vertex and texture
  397.  * coordinates.
  398.  *
  399.  * Parameters:
  400.  *   o tSippGlobPtr (I) - A pointer to the Tcl SIPP global structure.
  401.  *   o listStr (I) - A Tcl list containing the vertex values to convert.
  402.  *   o vertexPtr (O) - The converted vertex is returned here.
  403.  *   o texturePtr (O) - The converted texture coordinates are returned here.
  404.  * Returns:
  405.  *   TRUE if the list and numbers are valid, FALSE if there is an error.
  406.  *-----------------------------------------------------------------------------
  407.  */
  408. bool
  409. TSippConvertVertexTex (tSippGlobPtr, listStr, vertexPtr, texturePtr)
  410.     tSippGlob_pt  tSippGlobPtr;
  411.     char         *listStr;
  412.     Vector       *vertexPtr;
  413.     Vector       *texturePtr;
  414. {
  415.     int      pairArgc,  coordArgc, idx;
  416.     char   **pairArgv, **coordArgv;
  417.     Vector  *currentPtr;
  418.  
  419.     if (Tcl_SplitList (tSippGlobPtr->interp, listStr, &pairArgc,
  420.                        &pairArgv) != TCL_OK)
  421.         return FALSE;
  422.  
  423.     if (pairArgc != 2) {
  424.         Tcl_AppendResult (tSippGlobPtr->interp, "vertex-texture list must be",
  425.                           " a list of two coordinates", (char *) NULL);
  426.         goto errorCleanup;
  427.     }
  428.  
  429.     currentPtr = vertexPtr;
  430.     for (idx = 0; idx < 2; idx++) {
  431.         if (Tcl_SplitList (tSippGlobPtr->interp, pairArgv [idx], &coordArgc,
  432.                            &coordArgv) != TCL_OK)
  433.             goto errorCleanup;
  434.  
  435.         if (coordArgc != 3) {
  436.             Tcl_AppendResult (tSippGlobPtr->interp, "vertex or point must be",
  437.                              " a list of three elements", (char *) NULL);
  438.             goto errorCleanup2;
  439.         }
  440.  
  441.         if (Tcl_GetDouble (tSippGlobPtr->interp, coordArgv [0],
  442.                            ¤tPtr->x) != TCL_OK)
  443.            goto errorCleanup2;
  444.         if (Tcl_GetDouble (tSippGlobPtr->interp, coordArgv [1],
  445.                            ¤tPtr->y) != TCL_OK)
  446.            goto errorCleanup2;
  447.         if (Tcl_GetDouble (tSippGlobPtr->interp, coordArgv [2],
  448.                            ¤tPtr->z) != TCL_OK)
  449.            goto errorCleanup2;
  450.  
  451.         ckfree (coordArgv);
  452.         currentPtr = texturePtr;
  453.     }
  454.     ckfree (pairArgv);
  455.     return TRUE;
  456.  
  457. errorCleanup2:
  458.     ckfree (coordArgv);
  459. errorCleanup:
  460.     ckfree (pairArgv);
  461.     return FALSE;
  462.  
  463. } /* TSippConvertVertexTex */
  464.  
  465. /*=============================================================================
  466.  * TSippConvertMatrix --
  467.  *   Convert a list of list of floating point numbers representing a 4x4 matrix
  468.  * into a matrix.  The first list element represents the first row, etc.
  469.  *
  470.  * Parameters:
  471.  *   o tSippGlobPtr (I) - A pointer to the Tcl SIPP global structure.
  472.  *   o listStr (I) - A Tcl list containing the matrix
  473.  *   o matrixPtr (O) - The converted mattix is returned here as a 4x3 matrix.
  474.  * Returns:
  475.  *   TRUE if the matrix is OK,  FALSE if there is an error.
  476.  *-----------------------------------------------------------------------------
  477.  */
  478. bool
  479. TSippConvertMatrix (tSippGlobPtr, listStr, matrixPtr)
  480.     tSippGlob_pt  tSippGlobPtr;
  481.     char         *listStr;
  482.     Transf_mat   *matrixPtr;
  483. {
  484.     int      numRows, numColumns, row, column; 
  485.     char   **rowArgv, **columnArgv;
  486.     double   value, expectValue;
  487.  
  488.     /*
  489.      * Split each row, then convert the columns in the row.
  490.      */
  491.  
  492.     if (Tcl_SplitList (tSippGlobPtr->interp, listStr, &numRows,
  493.                        &rowArgv) != TCL_OK)
  494.         return FALSE;
  495.     if (numRows != 4) {
  496.         Tcl_AppendResult (tSippGlobPtr->interp, "matrix must have 4 rows",
  497.                           (char *) NULL);
  498.         goto rowErrorExit;
  499.     }
  500.     for (row = 0; row < 4; row++) {
  501.         if (Tcl_SplitList (tSippGlobPtr->interp, rowArgv [row], &numColumns,
  502.                            &columnArgv) != TCL_OK)
  503.             goto rowErrorExit;
  504.         if (numColumns != 4) {
  505.             Tcl_AppendResult (tSippGlobPtr->interp, 
  506.                               "matrix must have 4 columns", (char *) NULL);
  507.             goto colErrorExit;
  508.         }
  509.         for (column = 0; column < 3; column++) {
  510.             if (Tcl_GetDouble (tSippGlobPtr->interp, columnArgv [column],
  511.                                &matrixPtr->mat [row][column]) != TCL_OK)
  512.                 goto colErrorExit;
  513.         }
  514.         /*
  515.          * Validate that the value of column 3 but don't save it.
  516.          */
  517.         if (numColumns == 4) {
  518.             if (Tcl_GetDouble (tSippGlobPtr->interp, columnArgv [column],
  519.                                &value) != TCL_OK)
  520.                 goto colErrorExit;
  521.  
  522.             expectValue = (row == 3) ? 1.0 : 0.0;
  523.             if (value != expectValue) {
  524.                 sprintf (tSippGlobPtr->interp->result,
  525.                         "matrix row %d, column 3 must have a value of %3.1f",
  526.                         row, expectValue);
  527.                 goto colErrorExit;
  528.             }
  529.         }
  530.         ckfree (columnArgv);
  531.     }
  532.     ckfree (rowArgv);
  533.     return TRUE;
  534.  
  535. colErrorExit:
  536.     ckfree (columnArgv);
  537. rowErrorExit:
  538.     ckfree (rowArgv);
  539.     return FALSE;
  540.  
  541. } /* TSippConvertMatrix */
  542.  
  543. /*=============================================================================
  544.  * TSippFormatMatrix --
  545.  *   Format a 4x4 matrix as a list of lists.
  546.  *
  547.  * Parameters:
  548.  *   o matrixPtr (I) - The matrix to format.
  549.  * Returns:
  550.  *   A dynamically ckalloced string contain the lists.
  551.  *-----------------------------------------------------------------------------
  552.  */
  553. char *
  554. TSippFormatMatrix (matrixPtr)
  555.    Transf_mat   *matrixPtr;
  556. {
  557. #   define ROW_BUF_SIZE  4*40
  558.     int    row; 
  559.     char  *rowArgv [4];
  560.     char   rowBuffers [4][ROW_BUF_SIZE];
  561.  
  562.     rowArgv [0] = rowBuffers [0];
  563.     rowArgv [1] = rowBuffers [1];
  564.     rowArgv [2] = rowBuffers [2];
  565.     rowArgv [3] = rowBuffers [3];
  566.  
  567.     for (row = 0; row < 4; row++)
  568.         sprintf (rowArgv [row], "%g %g %g %g",
  569.                  matrixPtr->mat [row][0], matrixPtr->mat [row][1],
  570.                  matrixPtr->mat [row][2], matrixCol3 [row]);
  571.     
  572.     return Tcl_Merge (4, rowArgv);
  573.  
  574. } /* TSippFormatMatrix */
  575.  
  576. /*=============================================================================
  577.  * TSippHandleListConvert --
  578.  *   Convert a list of handles into an array of generic pointers.  This assumes
  579.  * that the handle entry consist of a single pointer.
  580.  *
  581.  * Parameters:
  582.  *   o tSippGlobPtr (I) - A pointer to the Tcl SIPP global structure.
  583.  *   o tableHdrPtr (I) - Pointer to the table header for the handles to
  584.  *     convert.
  585.  *   o listPtr (I) - The list to convert.
  586.  *   o handleListPtr (O) - A handle list structure, which be contain the
  587.  *     array of generic pointers.  HandleListFree must be called to
  588.  *     clean up this structure.
  589.  *   o handleEntryListPtr (O) - A handle list structure, which be contain the
  590.  *     array of generic pointers to the actual handle entry.  This is required
  591.  *     if the handle entries are to be freed.  If NULL is specified, the list
  592.  *     is not returned. HandleListFree must be called to clean up this
  593.  *     structure.
  594.  * Returns:
  595.  *   TRUE if the conversion succeeds, FALSE and an error in
  596.  * tSippGlobPtr->interp->result if an error occurs.
  597.  *-----------------------------------------------------------------------------
  598.  */
  599. bool
  600. TSippHandleListConvert (tSippGlobPtr, handleTblPtr, listPtr, handleListPtr,
  601.                         handleEntryListPtr)
  602.     tSippGlob_pt   tSippGlobPtr;
  603.     void          *handleTblPtr;
  604.     char          *listPtr;
  605.     handleList_pt  handleListPtr;
  606.     handleList_pt  handleEntryListPtr;
  607. {
  608.     int     handleArgc, idx, idx2;
  609.     char  **handleArgv;
  610.     void  **handleEntryPtr;
  611.  
  612.     if (Tcl_SplitList (tSippGlobPtr->interp, listPtr, &handleArgc,
  613.                        &handleArgv) != TCL_OK)
  614.         return FALSE;
  615.     if (handleArgc > HANDLE_LIST_STATIC_SIZE) {
  616.         handleListPtr->ptr = (void **) ckalloc (handleArgc * sizeof (void *));
  617.     } else {
  618.         handleListPtr->ptr = handleListPtr->staticArray;
  619.     }
  620.     handleListPtr->len = handleArgc;
  621.     if (handleEntryListPtr != NULL) {
  622.         if (handleArgc > HANDLE_LIST_STATIC_SIZE) {
  623.             handleEntryListPtr->ptr = (void **) 
  624.                 ckalloc (handleArgc * sizeof (void *));
  625.         } else {
  626.             handleEntryListPtr->ptr = handleEntryListPtr->staticArray;
  627.         }
  628.         handleEntryListPtr->len = handleArgc;
  629.     }
  630.     for (idx = 0; idx < handleArgc; idx++) {
  631.         handleEntryPtr = (void **)
  632.             Tcl_HandleXlate (tSippGlobPtr->interp, handleTblPtr,
  633.                              handleArgv [idx]);
  634.         if (handleEntryPtr == NULL)
  635.             goto errorExit;
  636.         handleListPtr->ptr [idx] = *handleEntryPtr;
  637.         if (handleEntryListPtr != NULL)
  638.             handleEntryListPtr->ptr [idx] = handleEntryPtr;
  639.     }
  640.  
  641.     /*
  642.      * Check for duplicate entries.
  643.      */
  644.     for (idx = 0; idx < handleArgc - 1; idx++) {
  645.         for (idx2 = idx + 1; idx2 < handleArgc; idx2++)
  646.             if (handleListPtr->ptr [idx2] == handleListPtr->ptr [idx]) {
  647.                  Tcl_AppendResult (tSippGlobPtr->interp, "duplicate handle ",
  648.                                   "in list: ", handleArgv [idx],
  649.                                   (char *) NULL);
  650.                  goto errorExit;
  651.             }
  652.     }
  653.  
  654.     ckfree (handleArgv);
  655.     return TRUE;
  656.  
  657. errorExit:
  658.     TSippHandleListFree (handleListPtr);
  659.     if (handleEntryListPtr != NULL)
  660.         TSippHandleListFree (handleEntryListPtr);
  661.     ckfree (handleArgv);
  662.     return FALSE;
  663.  
  664. } /* TSippHandleListConvert */
  665.  
  666. /*=============================================================================
  667.  * TSippHandleListFree --
  668.  *    Free the array in an handle handle list, if it was dynamically allocated.
  669.  *
  670.  * Parameters:
  671.  *   o handleListPtr (I) - The handle list structure.
  672.  *-----------------------------------------------------------------------------
  673.  */
  674. void
  675. TSippHandleListFree (handleListPtr)
  676.     handleList_pt  handleListPtr;
  677. {
  678.     if (handleListPtr->ptr != handleListPtr->staticArray)
  679.         ckfree (handleListPtr->ptr);
  680.  
  681. } /* TSippHandleListFree */
  682.  
  683. /*=============================================================================
  684.  * TSippInitCmds --
  685.  *   Given a command table, initialize the Tcl commands listed in it, with
  686.  * the Tcl SIPP globals as client data.
  687.  *
  688.  * Parameters:
  689.  *   o tSippGlobPtr (I) - A pointer to the Tcl SIPP global structure.
  690.  *   o cmdTablePtr (I) - A table of commands and there executors.  Terminated
  691.  *     by a entry of NULLs.
  692.  *-----------------------------------------------------------------------------
  693.  */
  694. void
  695. TSippInitCmds (tSippGlobPtr, cmdTablePtr)
  696.     tSippGlob_pt       tSippGlobPtr;
  697.     tSippTclCmdTbl_t  *cmdTablePtr;
  698. {
  699.     while (cmdTablePtr->name != NULL) {
  700.         Tcl_CreateCommand (tSippGlobPtr->interp, 
  701.                           cmdTablePtr->name, cmdTablePtr->proc,
  702.                           (ClientData) tSippGlobPtr, (void (*)())NULL);
  703.         cmdTablePtr++;
  704.     }
  705.  
  706. } /* TSippInitCmds */
  707.  
  708. /*=============================================================================
  709.  * TSippParseRenderParms --
  710.  *   Utility procedure to parse the parameters common to the rendering 
  711.  * commands.  All parameters are handled except for the file identifier. A
  712.  * pointer to the file ID is returned in the parameters to parse latter.
  713.  * The command is in the form:
  714.  *
  715.  *  cmd [-flag] fileid xsize ysize [mode] [oversample]",
  716.  *
  717.  * Parameters:
  718.  *   o tSippGlobPtr (I) - A pointer to the Tcl SIPP global structure.
  719.  *     Errors are returned in interp->result.
  720.  *   o argc, arrgv (I) - Arguments to the command.
  721.  *   o fileTitle (I) - The string to print out for the file in an error msg.
  722.  *   o renderParmsPtr (O) - The rendering parameters are returned here.
  723.  * Returns:
  724.  *   TRUE if all is ok, FALSE if an error occured.
  725.  *-----------------------------------------------------------------------------
  726.  */
  727. bool
  728. TSippParseRenderParms (tSippGlobPtr, argc, argv, fileTitle, renderParmsPtr)
  729.     tSippGlob_pt        tSippGlobPtr;
  730.     int                 argc;
  731.     char               **argv;
  732.     char                *fileTitle;
  733.     tSippRenderParms_pt  renderParmsPtr;
  734. {
  735.     int firstArg;
  736.  
  737.     if ((argc < 4) || (argc > 7))
  738.         goto usageErr;
  739.  
  740.     if (argv [1][0] == '-') {
  741.         if (STREQU (argv [1], "-BOTH")) {
  742.             renderParmsPtr->interlaced = FALSE;
  743.             renderParmsPtr->field      = 0;
  744.         } else if (STREQU (argv [1], "-ODD")) {
  745.             renderParmsPtr->interlaced = TRUE;
  746.             renderParmsPtr->field      = ODD;
  747.         } else if (STREQU (argv [1], "-EVEN")) {
  748.             renderParmsPtr->interlaced = TRUE;
  749.             renderParmsPtr->field      = EVEN;
  750.         } else {
  751.             Tcl_AppendResult (tSippGlobPtr->interp, "expected one of ",
  752.                               "\"-BOTH\", \"-OLD\", or \"-EVEN\", got \"",
  753.                               argv [1], "\"", (char *) NULL);
  754.             return FALSE;
  755.         }
  756.         firstArg = 2;
  757.     } else {
  758.         if (argc > 6)
  759.             goto usageErr;
  760.         renderParmsPtr->interlaced = FALSE;
  761.         renderParmsPtr->field      = 0;
  762.         firstArg = 1;
  763.     }
  764.  
  765.     renderParmsPtr->fileHandle = argv [firstArg];
  766.  
  767.     if (!TSippConvertPosUnsigned (tSippGlobPtr, argv [firstArg + 1],
  768.                                   &renderParmsPtr->xSize))
  769.         return FALSE;
  770.  
  771.     if (!TSippConvertPosUnsigned (tSippGlobPtr, argv [firstArg + 2],
  772.                                   &renderParmsPtr->ySize))
  773.         return FALSE;
  774.  
  775.     if ((firstArg + 3 >= argc) || (argv [firstArg + 3][0] == '\0')) {
  776.         renderParmsPtr->mode = PHONG;
  777.     } else {
  778.         if (STREQU (argv [firstArg + 3], "PHONG"))
  779.             renderParmsPtr->mode = PHONG;
  780.         else if (STREQU (argv [firstArg + 3], "GOURAUD"))
  781.             renderParmsPtr->mode = GOURAUD;
  782.         else if (STREQU (argv [firstArg + 3], "FLAT"))
  783.             renderParmsPtr->mode = FLAT;
  784.         else if (STREQU (argv [firstArg + 3], "LINE")) {
  785.             renderParmsPtr->mode = LINE;
  786.         } else {
  787.             Tcl_AppendResult (tSippGlobPtr->interp, "invalid rendering mode, ",
  788.                               "expect one of `PHONG', `GOURAUD', `FLAT', ",
  789.                               "or `LINE', got: ", argv [firstArg + 3],
  790.                               (char *) NULL);
  791.             return FALSE;
  792.         }
  793.     }
  794.  
  795.     if ((firstArg + 4 >= argc) || (argv [firstArg + 4][0] == '\0')) {
  796.         renderParmsPtr->overSampling = 1;
  797.     } else {
  798.         if (!TSippConvertPosUnsigned (tSippGlobPtr, argv [firstArg + 4],
  799.                                       &renderParmsPtr->overSampling))
  800.             return FALSE;
  801.     }
  802.  
  803.     if (renderParmsPtr->mode == LINE) {
  804.         if (renderParmsPtr->interlaced) {
  805.             Tcl_AppendResult (tSippGlobPtr->interp, "Can't specify \"-ODD\" ",
  806.                               "or \"-EVEN\" with a mode of \"LINE\"",
  807.                               (char *) NULL);
  808.             return FALSE;
  809.         }
  810.         renderParmsPtr->overSampling = 1;
  811.     }
  812.  
  813.     return TRUE;
  814.  
  815.   usageErr:
  816.     Tcl_AppendResult (tSippGlobPtr->interp, "wrong # args: ", argv [0],
  817.                       " [-flag] ", fileTitle,
  818.                       " xsize ysize [mode] [oversample]", (char *) NULL);
  819.     return FALSE;
  820.  
  821. } /* TSippParseRenderParms */
  822.  
  823. /*=============================================================================
  824.  * TSippParseTextureMapping --
  825.  *   Utility procedure to parse thetexture mapping parameter supplied to
  826.  * the object-creation primitive commands.
  827.  *
  828.  * Parameters:
  829.  *   o tSippGlobPtr (I) - A pointer to the Tcl SIPP global structure.
  830.  *     Errors are returned in interp->result.
  831.  *   o textureStr (I) - The texture mapping string to parse.
  832.  *   o texturePtr (O) - The parsed texture mapping is returned here.
  833.  *   o invalidList (I) - A list  of texture mappings that are not valid for the
  834.  *     command, Terminated by an entry containing -1.  NULL is all are valid.
  835.  * Returns:
  836.  *   TRUE if all is ok, FALSE if an error occured.
  837.  *-----------------------------------------------------------------------------
  838.  */
  839. bool
  840. TSippParseTextureMapping (tSippGlobPtr, textureStr, texturePtr, invalidList)
  841.     tSippGlob_pt    tSippGlobPtr;
  842.     char           *textureStr;
  843.     int            *texturePtr;
  844.     int            *invalidList;
  845. {
  846.     int texture;
  847.  
  848.     if ((textureStr [0] == '\0') || (STREQU (textureStr, "NATURAL"))) {
  849.         texture = NATURAL;
  850.     } else if (STREQU (textureStr, "CYLINDRICAL")) {
  851.         texture = CYLINDRICAL;
  852.     } else if (STREQU (textureStr, "SPHERICAL")) {
  853.         texture = SPHERICAL;
  854.     } else if (STREQU (textureStr, "WORLD")) {
  855.         texture = WORLD;
  856.     } else {
  857.         Tcl_AppendResult (tSippGlobPtr->interp, "expected one of ",
  858.                           "\"NATURAL\", \"CYLINDRICAL\", \"SPHERICAL\", or ",
  859.                           "\"WORLD\", got \"", textureStr, "\"",
  860.                           (char *) NULL);
  861.         return FALSE;
  862.     }
  863.  
  864.     if (invalidList != NULL) {
  865.         int idx;
  866.  
  867.         for (idx = 0; invalidList [idx] != -1; idx++) {
  868.             if (texture == invalidList [idx]) {
  869.                 Tcl_AppendResult (tSippGlobPtr->interp, "texture mapping ",
  870.                                   textureStr, " is not valid for this command",
  871.                                   (char *) NULL);
  872.                 return FALSE;
  873.             }
  874.         }
  875.     }
  876.  
  877.     *texturePtr = texture;
  878.     return TRUE;
  879.  
  880. } /* TSippParseTextureMapping */
  881.